package ir.values;

import ir.types.FunctionType;
import ir.types.datatypes.DataType;
import ir.types.datatypes.IntegerType;
import ir.types.datatypes.PointerType;
import ir.types.datatypes.VoidType;
import utils.BBList;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class FunctionIr extends Value {
    private final BBList<BasicBlock> basicBlocks = new BBList<>();
    private final ArrayList<Argument> arguments;
    private final boolean isBuiltin;
    private static FunctionType getFunctionType(DataType returnedType, ArrayList<Argument> arguments) {
        ArrayList<DataType> paramTypes = new ArrayList<>();
        for (Argument argument: arguments) {
            paramTypes.add(argument.getDataType());
        }
        return new FunctionType(returnedType, paramTypes);
    }
    public FunctionIr(String originalName, boolean isBuiltin, DataType returnedType, ArrayList<Argument> arguments) {
        super(originalName, getFunctionType(returnedType, arguments));
        this.isBuiltin = isBuiltin;
        this.arguments = arguments;
        basicBlocks.insertTail(new BasicBlock());
    }


    public FunctionType getFunctionType() {
        return (FunctionType) type;
    }
    public DataType getReturnType() {
        return getFunctionType().getReturnType();
    }
    @Override
    public String parseUsingName() {
        return "@" + originalName;
    }
    @Override
    public String parseLLVM() {
        // 生成子元素名字
        FunctionIrIdGenerator functionIrIdGenerator = new FunctionIrIdGenerator(this);
        functionIrIdGenerator.generateNames();

        // 构建StringBuilder
        StringBuilder sb = new StringBuilder();

        if (isBuiltin) {
            sb
                    .append("declare dso_local ")
                    .append(getFunctionType().getReturnType().toString())
                    .append(" ")
                    .append(parseUsingName())
                    .append("(");

            ArrayList<DataType> paramTypes = getFunctionType().getParamTypes();
            for (int i = 0; i < paramTypes.size(); i++) {
                sb.append(paramTypes.get(i).toString());
                if (i != paramTypes.size() - 1) {
                    sb.append(", ");
                }
            }
            sb.append(")\n");
        }

        else {
            // 函数头
            sb
                    .append("define dso_local ")
                    .append(getFunctionType().getReturnType().toString())
                    .append(" ")
                    .append(parseUsingName())
                    .append("(");

            // 参数列表
            for (int i = 0; i < arguments.size(); i++) {
                sb.append(arguments.get(i).parseLLVM());
                if (i != arguments.size() - 1) {
                    sb.append(", ");
                }
            }
            sb.append(") {\n");

            // 函数体
            for (BasicBlock basicBlock: basicBlocks) {
                sb.append(basicBlock.parseLLVM()).append("\n");
            }

            // 结尾
            sb.append("}\n");
        }

        return sb.toString();
    }

    public BBList<BasicBlock> getBasicBlocks() {
        return basicBlocks;
    }


    public ArrayList<Argument> getArguments() {
        return arguments;
    }

    public boolean isBuiltin() {
        return isBuiltin;
    }
}
